using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Trigits
{
    class GridFace
    {
        private GridPoint[] vertices;
        private bool filled = false;
        private VertexPositionColor[] lineVertex;
        private VertexPositionColor[] fillVertex;
        private Color fillColor = Color.FromNonPremultiplied(new Vector4(0.75f,0.75f,0.75f,0.5f));
        private Color lineColor = Color.Gray;
        private AnchoredText[] valueText;
        private SpriteFont font;
        private float scale;

        public GridFace(GridPoint point1, GridPoint point2, GridPoint point3, SpriteFont font, float scale)
        {
            this.scale = scale;
            this.font = font;
            lineVertex = new VertexPositionColor[4];
            fillVertex = new VertexPositionColor[4];

            vertices = new GridPoint[3];
            vertices[0] = point1;
            vertices[1] = point2;
            vertices[2] = point3;

            setVertices();
            setText();
        }

        public void setText()
        {
            valueText = new AnchoredText[3];

            Vector2 center = getCenter(
                vertices[0].getLocation(),
                vertices[1].getLocation(),
                vertices[2].getLocation()
                );

            for (int i = 0; i < 3; i++)
            {
                Vector2 vertex = new Vector2(
                        (center.X + lineVertex[i].Position.X) / 2,
                        (center.Y + lineVertex[i].Position.Y) / 2);

                Vector2 dist = vertex - center;
                dist.Normalize();
                float angle = (float) Math.Atan(dist.Y / dist.X);
                
                if (dist.X < 0)
                    angle += MathHelper.ToRadians(180);

                angle += MathHelper.ToRadians(90);

                valueText[i] = new AnchoredText(
                    font,
                    vertices[i].getValue().ToString(),
                    vertex,
                    angle,
                    TextAnchor.MiddleCenter,
                    scale);
            }
        }

        private void setVertices()
        {
            for (int i = 0; i < 3; i++)
            {
                lineVertex[i] = new VertexPositionColor(
                    new Vector3(
                        vertices[i].getLocation().X,
                        vertices[i].getLocation().Y,
                        0.0f),
                    lineColor);
                fillVertex[i] = new VertexPositionColor(
                    new Vector3(
                        vertices[i].getLocation().X,
                        vertices[i].getLocation().Y,
                        0.0f),
                    fillColor);
            }

            fillVertex[3].Position = fillVertex[0].Position;
            lineVertex[3].Position = fillVertex[0].Position;
            fillVertex[3].Color = fillColor;
            lineVertex[3].Color = lineColor;
            
        }

        public Vector2 getCenter(Vector2 a, Vector2 b, Vector2 c)
        {
            Vector2 side1center = new Vector2((a.X + b.X) / 2, (a.Y + b.Y) / 2);
            Vector2 side2center = new Vector2((b.X + c.X) / 2, (b.Y + c.Y) / 2);

            float[] one = getLineEquation(side1center, c);
            float[] two = getLineEquation(side2center, a);

            float x, y;

            // get intersection
            if(float.IsInfinity(one[0]) || float.IsInfinity(one[1]))
            { // line one is vertical
                x = side1center.X;
                y = two[0] + two[1] * x;
            }
            else if (float.IsInfinity(two[0]) || float.IsInfinity(two[1]))
            { // line two is vertical
                x = side2center.X;
                y = one[0] + one[1] * x;
            }
            else
            { // none are vertical
                x = (two[0] - one[0]) / (one[1] - two[1]);
                y = one[1] * x + one[0];
            }

            // return the intersection
            return new Vector2(x, y);
        }

        // returns an array of floats with two elements.
        // This array represents a line equation in the form of
        // f[0] + x * f[1] = y
        private float[] getLineEquation(Vector2 a, Vector2 b)
        {
            float dx = b.X - a.X;
            float dy = b.Y - a.Y;
            float r  = dy / dx; // slope
            float m  = b.Y - r * b.X; // intercept at X-axis

            float[] eq = { m, r };

            return eq;
        }

        public void setFilled()
        {
            filled = true;
            for (int i = 0; i < 3; i++)
            {
                fillVertex[i].Color = fillColor = Color.PaleGoldenrod;
                lineVertex[i].Color = lineColor = Color.Black;
            }
        }

        public bool isFilled()
        {
            return filled;
        }

        public bool hasVertex(GridPoint p)
        {
            foreach (GridPoint g in vertices)
            {
                float x = p.getLocation().X - g.getLocation().X;
                float y = p.getLocation().Y - g.getLocation().Y;

                x *= x;
                y *= y;

                if (x < 1 && y < 1)
                    return true;
            }

            return false;
        }

        public GridPoint[] getPoints()
        {
            return vertices;
        }

        public bool containsPoint(float x, float y)
        {
            Vector2 ab = new Vector2(
                vertices[0].getLocation().X - vertices[1].getLocation().X,
                vertices[0].getLocation().Y - vertices[1].getLocation().Y);
            Vector2 ap = new Vector2(
                vertices[0].getLocation().X - x,
                vertices[0].getLocation().Y - y);
            float abp = ap.X * ab.Y - ap.Y * ab.X;

            Vector2 bc = new Vector2(
                vertices[1].getLocation().X - vertices[2].getLocation().X,
                vertices[1].getLocation().Y - vertices[2].getLocation().Y);
            Vector2 bp = new Vector2(
                vertices[1].getLocation().X - x,
                vertices[1].getLocation().Y - y);
            float bcp = bp.X * bc.Y - bp.Y * bc.X;

            if (abp >= 0 && bcp < 0 ||
                abp < 0 && bcp >= 0)
                return false;

            Vector2 ca = new Vector2(
                vertices[2].getLocation().X - vertices[0].getLocation().X,
                vertices[2].getLocation().Y - vertices[0].getLocation().Y);
            Vector2 cp = new Vector2(
                vertices[2].getLocation().X - x,
                vertices[2].getLocation().Y - y);
            float cap = cp.X * ca.Y - cp.Y * ca.X;

            if (bcp >= 0 && cap < 0 ||
                bcp < 0 && cap >= 0)
                return false;

            return true;
        }

        public void Draw(GraphicsDevice graphics, SpriteBatch spriteBatch, SpriteFont font)
        {
            graphics.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.TriangleStrip, fillVertex, 0, 1);

            graphics.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.LineStrip, lineVertex, 0, 3);

            if(filled)
                for (int i = 0; i < 3; i++)
                    valueText[i].Draw(spriteBatch);
        }

        public bool isPointingRight()
        {
            float d;
            d = vertices[0].getLocation().X - vertices[1].getLocation().X;
            if (d * d < 1)
            {
                if (vertices[2].getLocation().X > vertices[0].getLocation().X + 10)
                    return true;
                else if (vertices[2].getLocation().X < vertices[0].getLocation().X - 10)
                    return false;
                else
                    throw new Exception("Can only match neatly rotated faces.");
            }

            d = vertices[1].getLocation().X - vertices[2].getLocation().X;
            if (d * d < 1)
            {
                if (vertices[0].getLocation().X > vertices[1].getLocation().X + 10)
                    return true;
                else if (vertices[0].getLocation().X < vertices[1].getLocation().X - 10)
                    return false;
                else
                    throw new Exception("Can only match neatly rotated faces.");
            }


            d = vertices[2].getLocation().X - vertices[0].getLocation().X;
            if (d * d < 1)
            {
                if (vertices[1].getLocation().X > vertices[2].getLocation().X + 10)
                    return true;
                else if (vertices[1].getLocation().X < vertices[2].getLocation().X - 10)
                    return false;
                else
                    throw new Exception("Can only match neatly rotated faces.");
            }

            throw new Exception("Can only match neatly rotated faces.");
        }

        public Vector2[] getVectors()
        {
            Vector2[] v = new Vector2[3];

            for (int i = 0; i < 3; i++)
            {
                v[i] = new Vector2(fillVertex[i].Position.X, fillVertex[i].Position.Y);
            }

            return v;
        }

        public void move(Vector2 distance)
        {
            setVertices();
            setText();

        }
    }
}
